package controller;

import controller.util.JsfUtil;
import facade.*;
import java.io.Serializable;
import java.util.*;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import modelo.*;

@ManagedBean(name = "compraController")
@SessionScoped
public class CompraController implements Serializable {

    private Compra current;
    private ItensCompra currentItensCompra;
    private CondicoesCompra currentCondicoesCompra;
    private Baixas currentBaixas;
    
    private DataModel items = null;
    private DataModel itemsItensCompra = null;
    private DataModel itemsCondicoesCompra = null;
    
    private List<ItensCompra> listItensCompraAUX;
    private List<CondicoesCompra> listCondicoesCompraAUX;
    
    @EJB
    private facade.CompraFacade ejbFacade;
    @EJB
    private facade.ItensCompraFacade ejbItensCompraFacade;
    @EJB
    private facade.ProdutoFacade ejbProdutoFacade;
    @EJB
    private facade.CondicoesCompraFacade ejbCondicoesCompraFacade;
    @EJB
    private facade.TituloFacade ejbTituloFacade;
    @EJB
    private facade.TituloPagarFacade ejbTituloPagarFacade;
    @EJB
    private facade.BaixasFacade ejbBaixasFacade;
    
    private double valorTotalCompra = 0;
    private double valorTotalCondicoesCompra = 0;
    
    private boolean renderizaItensCompra = false;
    private boolean renderizaCondicoesCompra = false;
    private boolean renderizaBotaoSalvar = false;
    private boolean renderizaEdicaoCompra = false;

    public CompraController() {
    }

    public Compra getSelected() {
        if (current == null) {
            current = new Compra();
        }
        return current;
    }

    public ItensCompra getItensCompraSelected() {
        if (currentItensCompra == null) {
            currentItensCompra = new ItensCompra();
        }
        return currentItensCompra;
    }

    public CondicoesCompra getCondicoesCompraSelected() {
        if (currentCondicoesCompra == null) {
            currentCondicoesCompra = new CondicoesCompra();
        }
        return currentCondicoesCompra;
    }

    public Baixas getBaixasSelected() {
        if (currentBaixas == null) {
            currentBaixas = new Baixas();
        }
        return currentBaixas;
    }

    private CompraFacade getFacade() {
        return ejbFacade;
    }

    private ItensCompraFacade getItensCompraFacade() {
        return ejbItensCompraFacade;
    }

    private ProdutoFacade getProdutoFacade() {
        return ejbProdutoFacade;
    }

    private CondicoesCompraFacade getCondicoesCompraFacade() {
        return ejbCondicoesCompraFacade;
    }

    private TituloFacade getTituloFacade() {
        return ejbTituloFacade;
    }

    private TituloPagarFacade getTituloPagarFacade() {
        return ejbTituloPagarFacade;
    }

    private BaixasFacade getBaixasFacade() {
        return ejbBaixasFacade;
    }

    public String prepareList() {
        recreateModel();
        recreateModelItensCompra();
        recreateModelCondicoesCompra();
        return "List";
    }

    public String prepareView() {
        setRenderizaItensCompra(true);
        current = (Compra) getItems().getRowData();
        recreateModelItensCompra();
        listItensCompraAUX = getItensCompraFacade().findByCompra(current);
        recreateModelCondicoesCompra();
        listCondicoesCompraAUX = getCondicoesCompraFacade().findByCompra(current);
        return "View";
    }

    public String prepareCreate() {
        setRenderizaItensCompra(false);
        current = new Compra(new Date());
        recreateModelItensCompra();
        listItensCompraAUX = new ArrayList<ItensCompra>();
        recreateModelCondicoesCompra();
        listCondicoesCompraAUX = new ArrayList<CondicoesCompra>();
        return "Create";
    }

    public void prepareCreateItensCompra(ActionEvent actionEvent) {
        currentItensCompra = new ItensCompra();
        currentItensCompra.setQuantidade(1.0);
    }

    public void prepareCreateCondicoesCompra(ActionEvent actionEvent) {
        currentCondicoesCompra = new CondicoesCompra();
        currentCondicoesCompra.setValor(valorTotalCompra - valorTotalCondicoesCompra);
    }

    public String create() {
        try {
            getFacade().create(current);

            for (ItensCompra i : listItensCompraAUX) {
                i.setCompra(current);
                i.getItensCompraPK().setIdCompra(current.getIdCompra());
                getItensCompraFacade().create(i);

                //atualizar informacoes de produto
                i.getProduto().setQuantidade(i.getProduto().getQuantidade() + i.getQuantidade());
                i.getProduto().setValor(i.getValor());
                getProdutoFacade().edit(i.getProduto());
            }

            for (CondicoesCompra c : listCondicoesCompraAUX) {

                c.setCompra(current);
                getCondicoesCompraFacade().create(c);

                int i = 0;
                int idTitulo = (getTituloFacade().getMaxIdTitulo() + 1);
                int parcela = 1;
                double valor = c.getValor() / c.getCondicaoPagamento().getVezes();

                //pegando data atual
                Calendar dataBase = Calendar.getInstance();
                dataBase.setTime(new Date());

                c.setTituloPagarList(new ArrayList<TituloPagar>());

                //loop de geracao de titulos
                while (i < c.getCondicaoPagamento().getVezes()) {

                    //somando um mes
                    if (i > 0 || !c.getCondicaoPagamento().isEntrada()) {
                        dataBase.add(Calendar.MONTH, 1);
                    }

                    //gerando titulos
                    TituloPagar tituloPagar =
                            new TituloPagar(idTitulo, parcela, new Date(), dataBase.getTime(), valor, c);
                    getTituloFacade().create(tituloPagar);
                    if (c.getCondicaoPagamento().isEntrada() && i == 0) {
                        getBaixasFacade().create(new Baixas(dataBase.getTime(), valor, tituloPagar));
                    }
                    i++;
                    parcela++;
                }

            }

            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("CompraCreated"));
            recreateModel();
            recreateModelItensCompra();
            return prepareList();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public void createItensCompra(ActionEvent actionEvent) {

        ItensCompraPK itensCompraPK = new ItensCompraPK();
        itensCompraPK.setItem(listItensCompraAUX.size() + 1);
        currentItensCompra.setItensCompraPK(itensCompraPK);

        listItensCompraAUX.add(currentItensCompra);
        itemsItensCompra = new ListDataModel(listItensCompraAUX);
        JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("ItensCompraCreated"));

    }

    public void createCondicoesCompra(ActionEvent actionEvent) {

        listCondicoesCompraAUX.add(currentCondicoesCompra);
        itemsCondicoesCompra = new ListDataModel(listCondicoesCompraAUX);
        JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("CondicoesCompraCreated"));

    }

    public String prepareEdit() {
        current = (Compra) getItems().getRowData();
        recreateModelItensCompra();
        listItensCompraAUX = getItensCompraFacade().findByCompra(current);
        current.setItensCompraList(listItensCompraAUX);
        recreateModelCondicoesCompra();
        listCondicoesCompraAUX = getCondicoesCompraFacade().findByCompra(current);
        return "Edit";
    }

    public void prepareEditItensCompra(ActionEvent actionEvent) {
        currentItensCompra = (ItensCompra) getItemsItensCompra().getRowData();
    }

    public void prepareEditCondicoesCompra(ActionEvent actionEvent) {
        currentCondicoesCompra = (CondicoesCompra) getItemsCondicoesCompra().getRowData();
    }

    public String update() {
        try {
            
            //retira quantidade adicionada na ultima edição
            for (ItensCompra i : current.getItensCompraList()) {
                i.getProduto().setQuantidade(i.getProduto().getQuantidade() - i.getQuantidade());
                getProdutoFacade().edit(i.getProduto());
            }
            
            //atualizando novas quantidades
            for (ItensCompra i : listItensCompraAUX) {
                i.setCompra(current);
                i.getItensCompraPK().setIdCompra(current.getIdCompra());

                //atualizar informacoes de produto
                i.getProduto().setQuantidade(i.getProduto().getQuantidade() +  i.getQuantidade());
                i.getProduto().setValor(i.getValor());
                //
            }

            for (CondicoesCompra c : listCondicoesCompraAUX) {

                c.setCompra(current);

                int i = 0;
                int idTitulo = getTituloFacade().getMaxIdTitulo();
                int parcela = 1;
                double valor = (c.getValor() / c.getCondicaoPagamento().getVezes());

                //pegando data atual
                Calendar dataBase = Calendar.getInstance();
                dataBase.setTime(new Date());

                //loop de geracao de titulos
                while (i < currentCondicoesCompra.getCondicaoPagamento().getVezes()) {

                    //somando um mes
                    dataBase.add(Calendar.MONTH, 1);

                    //gerando titulos
                    TituloPagar tituloPagar =
                            new TituloPagar(idTitulo, parcela, new Date(), dataBase.getTime(), valor, currentCondicoesCompra);
                    c.getTituloPagarList().add(tituloPagar);
                    i++;
                    parcela++;
                }

            }

            current.setItensCompraList(listItensCompraAUX);
            current.setCondicoesCompraList(listCondicoesCompraAUX);

            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("CompraUpdated"));
            return prepareList();
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public void updateItensCompra(ActionEvent actionEvent) {
        try {
            listItensCompraAUX.set(listItensCompraAUX.indexOf(currentItensCompra), currentItensCompra);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("ItensCompraUpdated"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    public void updateCondicoesCompra(ActionEvent actionEvent) {
        try {
            listCondicoesCompraAUX.set(listCondicoesCompraAUX.indexOf(currentCondicoesCompra), currentCondicoesCompra);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("CondicoesCompraUpdated"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    public String destroy() {
        current = (Compra) getItems().getRowData();
        current.setItensCompraList(listItensCompraAUX);
        current.setCondicoesCompraList(listCondicoesCompraAUX);

        for (ItensCompra i : current.getItensCompraList()) {

            //atualizar informacoes de produto
            i.getProduto().setQuantidade(i.getProduto().getQuantidade() - i.getQuantidade());
            getProdutoFacade().edit(i.getProduto());
            //
        }

        performDestroy();
        recreateModel();
        return "List";
    }

    public void destroyItensCompra(ActionEvent actionEvent) {
        currentItensCompra = (ItensCompra) getItemsItensCompra().getRowData();
        performDestroyItensCompra();
        recreateModelItensCompra();
    }

    public void destroyCondicoesCompra(ActionEvent actionEvent) {
        currentCondicoesCompra = (CondicoesCompra) getItemsCondicoesCompra().getRowData();
        performDestroyCondicoesCompra();
        recreateModelCondicoesCompra();
    }

    private void performDestroy() {
        try {
            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("CompraDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    private void performDestroyItensCompra() {
        listItensCompraAUX.remove(currentItensCompra);
    }

    private void performDestroyCondicoesCompra() {
        listCondicoesCompraAUX.remove(currentCondicoesCompra);
    }

    public DataModel getItems() {
        if (items == null) {
            items = new ListDataModel(getFacade().findAll());
        }
        return items;
    }

    public DataModel getItemsItensCompra() {
        if (itemsItensCompra == null) {
            if (current.getIdCompra() != null) {
                itemsItensCompra = new ListDataModel(listItensCompraAUX);
            } else {
                itemsItensCompra = new ListDataModel();
            }
        }
        return itemsItensCompra;
    }

    public DataModel getItemsCondicoesCompra() {
        if (itemsCondicoesCompra == null) {
            if (current.getIdCompra() != null) {
                itemsCondicoesCompra = new ListDataModel(listCondicoesCompraAUX);
            } else {
                itemsCondicoesCompra = new ListDataModel();
            }
        }
        return itemsCondicoesCompra;
    }

    private void recreateModel() {
        items = null;
    }

    private void recreateModelItensCompra() {
        itemsItensCompra = null;
    }

    private void recreateModelCondicoesCompra() {
        itemsCondicoesCompra = null;
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
    }

    public double getValorTotalCompra() {
        valorTotalCompra = 0;
        for (ItensCompra i : listItensCompraAUX) {
            valorTotalCompra += (i.getValor() * i.getQuantidade());
        }
        return valorTotalCompra;
    }

    public double getValorTotalCondicoesCompra() {
        valorTotalCondicoesCompra = 0;
        for (CondicoesCompra c : listCondicoesCompraAUX) {
            valorTotalCondicoesCompra += (c.getValor());
        }
        return valorTotalCondicoesCompra;
    }

    public void gatilharValor() {
        UIInput ui = (UIInput) findComponent(FacesContext.getCurrentInstance().getViewRoot(),
                "itensCompraProdutoCreate");
        String s = (String) ui.getSubmittedValue();
        Produto p = getProdutoFacade().findByIdProduto(Integer.parseInt(s));
        currentItensCompra.setValor(p.getValor());
    }

    protected UIComponent findComponent(UIComponent parent, String id) {
        if (id == null) {
            return null;
        }

        if (id.equals(parent.getId())) {
            return parent;
        }

        Iterator<UIComponent> kids = parent.getFacetsAndChildren();
        while (kids.hasNext()) {
            UIComponent kid = kids.next();
            UIComponent found = findComponent(kid, id);
            if (found != null) {
                return found;
            }
        }
        return null;
    }

    public boolean isRenderizaItensCompra() {
        return renderizaItensCompra;
    }

    public void setRenderizaItensCompra(boolean renderizaItensCompra) {
        this.renderizaItensCompra = renderizaItensCompra;
    }

    public boolean isRenderizaCondicoesCompra() {
        return renderizaCondicoesCompra;
    }

    public void setRenderizaCondicoesCompra(boolean renderizaCondicoesCompra) {
        this.renderizaCondicoesCompra = renderizaCondicoesCompra;
    }

    public void mostrarItensCompra() {
        setRenderizaItensCompra(true);
    }

    public void mostrarCondicoesCompra() {
        setRenderizaCondicoesCompra(true);
    }

    public boolean isRenderizaBotaoSalvar() {
        renderizaBotaoSalvar = ((getValorTotalCompra() == getValorTotalCondicoesCompra())
                && (getValorTotalCompra() > 0));
        return renderizaBotaoSalvar;
    }
    
    public boolean isRenderizaEdicaoCompra() {
        renderizaEdicaoCompra = false;
        if (getCondicoesCompraFacade().findByCompra(current) == null){
            renderizaEdicaoCompra = true;
        }
        return renderizaEdicaoCompra;
    }

    @FacesConverter(forClass = Compra.class)
    public static class CompraControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            CompraController controller = (CompraController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "compraController");
            return controller.ejbFacade.find(getKey(value));
        }

        java.lang.Integer getKey(String value) {
            java.lang.Integer key;
            key = Integer.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Integer value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Compra) {
                Compra o = (Compra) object;
                return getStringKey(o.getIdCompra());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + CompraController.class.getName());
            }
        }
    }
}